package com.ruoyi.recycle.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.bean.BeanUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.recycle.domain.*;
import com.ruoyi.recycle.dto.CouponDto;
import com.ruoyi.recycle.dto.ShopLabelsDTO;
import com.ruoyi.recycle.dto.ShopManagementDTO;
import com.ruoyi.recycle.exception.BusinessException;
import com.ruoyi.recycle.mapper.CouponMapper;
import com.ruoyi.recycle.mapper.CouponStockMapper;
import com.ruoyi.recycle.mapper.ShopManagementMapper;
import com.ruoyi.recycle.mapper.SysTypeConfigMapper;
import com.ruoyi.recycle.properties.Wxproperties;
import com.ruoyi.recycle.service.IMerchantManagementService;
import com.ruoyi.recycle.service.IShopManagementService;
import com.ruoyi.system.api.RemoteLoginService;
import com.ruoyi.system.api.RemoteUserService;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.form.RegisterBody;
import com.ruoyi.system.api.model.LoginUser;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 引流门店管理Service业务层处理
 *
 * @author Wubk
 * @date 2022-05-21
 */
@Service
@Slf4j
public class ShopManagementServiceImpl extends ServiceImpl<ShopManagementMapper, ShopManagement> implements IShopManagementService {
    @Autowired
    private ShopManagementMapper shopManagementMapper;
    @Autowired
    private RemoteLoginService remoteLoginService;
    @Autowired
    private RemoteUserService userService;
    @Resource
    private SysTypeConfigMapper sysTypeConfigMapper;
    @Resource
    private CouponMapper couponMapper;
    @Resource
    private CouponStockMapper couponStockMapper;
    @Autowired
    private IMerchantManagementService merchantManagementService;
    @Autowired
    private Wxproperties wxproperties;

    /**
     * 查询引流门店管理
     *
     * @param id 引流门店管理主键
     * @return 引流门店管理
     */
    @Override
    public ShopManagement selectShopManagementById(Long id) {
        return shopManagementMapper.selectShopManagementById(id);
    }

    /**
     * 查询引流门店管理列表
     *
     * @param shopManagement 引流门店管理
     * @return 引流门店管理
     */
    @Override
    public List<ShopManagement> selectShopManagementList(ShopManagement shopManagement) {
        return shopManagementMapper.selectShopManagementList(shopManagement);
    }

    /**
     * 新增引流门店管理
     *
     * @param shopManagement 引流门店管理
     * @return 结果
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public int insertShopManagement(ShopManagement shopManagement) {
        final R<?> register = remoteLoginService
                .register(new RegisterBody()
                        .setUsername(shopManagement.getShopNumber())
                        .setPassword(shopManagement.getShopPassword()));
        if (StrUtil.isNotEmpty(register.getMsg())) {
            throw new BusinessException(StrUtil.format("注册失败,原因:{}", register.getMsg()));
        }
        final R<LoginUser> userInfo = userService.getUserInfo(shopManagement.getShopNumber(), SecurityConstants.INNER);
        final Long userId = userInfo.getData().getSysUser().getUserId();
        final MerchantManagement management = merchantManagementService.getById(shopManagement.getMerchantId());
        String merchantName = management != null ? management.getMerchantName() : null;
        if (StrUtil.isEmpty(shopManagement.getHeadPortrait())) {
            shopManagement.setHeadPortrait(wxproperties.getDefaultPortrait());
        }
        return save(shopManagement.setUserId(userId).setMerchantName(merchantName).setStatus("1")) ? 1 : 0;
    }

    /**
     * 修改引流门店管理
     *
     * @param shopManagement 引流门店管理
     * @return 结果
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public int updateShopManagement(ShopManagement shopManagement) {
        final R<LoginUser> info = userService.getUserInfo(shopManagement.getShopNumber(), SecurityConstants.INNER);
        Assert.isTrue(info.getCode() == 200, () -> new BusinessException("该账号未注册到系统中"));
        if (StrUtil.isNotEmpty(shopManagement.getShopPassword())) {
            final SysUser sysUser = new SysUser();
            sysUser.setUserId(info.getData().getSysUser().getUserId());
            sysUser.setUserName(shopManagement.getShopNumber());
            sysUser.setPassword(shopManagement.getShopPassword());
            final AjaxResult result = userService.resetPwd(sysUser, SecurityConstants.INNER);
            Assert.isTrue((int) result.get("code") == 200, () -> new BusinessException(StrUtil.format("修改门店信息错误,原因:{}", result.get("msg"))));

        }


        return shopManagementMapper.updateById(shopManagement);
    }

    /**
     * 批量删除引流门店管理
     *
     * @param ids 需要删除的引流门店管理主键
     * @return 结果
     */
    @Override
    public int deleteShopManagementByIds(Long[] ids) {
        final List<ShopManagement> managementList = list(Wrappers.lambdaQuery(new ShopManagement()).in(ShopManagement::getId, Arrays.asList(ids)));
        userService.remove(managementList.stream().map(ShopManagement::getUserId).toArray(Long[]::new), SecurityConstants.INNER);
        return shopManagementMapper.deleteShopManagementByIds(ids);
    }

    /**
     * 删除引流门店管理信息
     *
     * @param id 引流门店管理主键
     * @return 结果
     */
    @Override
    public int deleteShopManagementById(Long id) {
        return shopManagementMapper.deleteShopManagementById(id);
    }

    @Override
    public AjaxResult nearbyShopRecommend(Double dis, Double longitude, Double latitude,Long clientId) {

        //先计算查询点的经纬度范围
        List<ShopManagement>  tshoplist = null;
        List<ShopManagementDTO> shopManagementDTOList = new ArrayList<>();
        try {
            double r = 6371;//地球半径千米
            double dlng =  2*Math.asin(Math.sin(dis/(2*r))/Math.cos(latitude*Math.PI/180));
            dlng = dlng*180/Math.PI;//角度转为弧度
            double dlat = dis/r;
            dlat = dlat*180/Math.PI;
            double minlat =latitude-dlat;
            double maxlat = latitude+dlat;
            double minlng = longitude -dlng;
            double maxlng = longitude + dlng;
            tshoplist = shopManagementMapper.selectshopnear(minlat,maxlat,minlng,maxlng);

            if (!CollectionUtils.isEmpty(tshoplist)){

                for (ShopManagement shopManagement : tshoplist) {
                    ShopManagementDTO shopManagementDTO = new ShopManagementDTO();
                    BeanUtils.copyProperties(shopManagement,shopManagementDTO);

                    double distance = getDistance(longitude, latitude, shopManagement.getLongitude(), shopManagement.getLatitude(),3);
                    shopManagementDTO.setDistance(distance);
                    Long count = shopManagementMapper.selectClientCollect(shopManagement.getId(),clientId);
                    shopManagementDTO.setCollectFlag(count>0?1:0);
                    shopManagementDTOList.add(shopManagementDTO);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("经纬度查询异常，异常信息为{}",e.getMessage(),e);
        }

        List<SysTypeConfig> sysTypeConfigList = sysTypeConfigMapper.selectList(new LambdaQueryWrapper<SysTypeConfig>().eq(SysTypeConfig::getType, "门店分类"));


        return AjaxResult.success(shopManagementDTOList).put("shop",sysTypeConfigList);
    }


    @Override
    public AjaxResult nearbyShopRecommend(Double dis, Double longitude, Double latitude, String name,Long clientId,String type) {
        //先计算查询点的经纬度范围
        List<ShopManagement>  tshoplist = null;
        List<ShopManagementDTO> shopManagementDTOList = new ArrayList<>();

        try {
            double r = 6371;//地球半径千米
            double dlng =  2*Math.asin(Math.sin(dis/(2*r))/Math.cos(latitude*Math.PI/180));
            dlng = dlng*180/Math.PI;//角度转为弧度
            double dlat = dis/r;
            dlat = dlat*180/Math.PI;
            double minlat =latitude-dlat;
            double maxlat = latitude+dlat;
            double minlng = longitude - dlng;
            double maxlng = longitude + dlng;
            tshoplist = shopManagementMapper.selectShopByName(minlat,maxlat,minlng,maxlng,name,type);

            if (!CollectionUtils.isEmpty(tshoplist)){

                for (ShopManagement shopManagement : tshoplist) {
                    ShopManagementDTO shopManagementDTO = new ShopManagementDTO();
                    BeanUtils.copyProperties(shopManagement,shopManagementDTO);

                    double distance = getDistance(longitude, latitude, shopManagement.getLongitude(), shopManagement.getLatitude(),3);
                    shopManagementDTO.setDistance(distance);

                    Long count = shopManagementMapper.selectClientCollect(shopManagement.getId(),clientId);

                    shopManagementDTO.setCollectFlag(count>0?1:0);
                    //设置门店优惠券
                    List<Coupon> couponList = couponMapper.selectList(new LambdaQueryWrapper<Coupon>().eq(Coupon::getShopId, shopManagement.getId().intValue()));
                    List<CouponDto> couponDtoList = new ArrayList<>();
                    for (Coupon coupon : couponList) {
                        CouponDto couponDto = new CouponDto();
                        BeanUtils.copyProperties(coupon,couponDto);
                        Integer selectCount = couponStockMapper.selectCount(new LambdaQueryWrapper<CouponStock>().eq(CouponStock::getCouponId, coupon.getId()).ne(CouponStock::getStatus, "已领取"));
                        if (selectCount<1){
                            couponDto.setStatus("0");
                        }
                        Integer clientHold = couponStockMapper.selectClientHold(clientId,coupon.getId());
                        if (clientHold > 0){
                            couponDto.setClientHold("Y");
                        }else {
                            couponDto.setClientHold("N");
                        }
                        couponDtoList.add(couponDto);
                    }
                    shopManagementDTO.setCouponList(couponDtoList);
                    shopManagementDTOList.add(shopManagementDTO);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("经纬度查询异常，异常信息为{}", e.getMessage(), e);
        }

        List<SysTypeConfig> sysTypeConfigList = sysTypeConfigMapper.selectList(new LambdaQueryWrapper<SysTypeConfig>().eq(SysTypeConfig::getType, "门店分类"));

        return AjaxResult.success(shopManagementDTOList).put("shop",sysTypeConfigList);
    }

    @Override
    public void addLabels(ShopLabelsDTO labels) {
        final List<String> labelList = labels.getLabels();
        final StringBuffer buffer = new StringBuffer();
        for (int i = 1; i <= labelList.size(); i++) {
            if (i != labelList.size()) {
                buffer.append(labelList.get(i - 1)).append(";");
            } else {
                buffer.append(labelList.get(i - 1));
            }
        }
        updateById(new ShopManagement().setId(labels.getShopId()).setLabels(buffer.toString()));
    }

    @Override
    public AjaxResult collectShopPageQuery(Long clientId, Integer currentPage, Integer pageSize) {

        List<ShopManagement> shopManagementList = shopManagementMapper.collectShopPageQuery(clientId);
        List<ShopManagement> subList = shopManagementList.stream().skip((currentPage-1)*pageSize).limit(pageSize).collect(Collectors.toList());
        return AjaxResult.success(subList).put("currentPage",currentPage).put("pageSize",pageSize).put("total",shopManagementList.size());

    }

    @Override
    public AjaxResult changeStatus(Long id, String status) {
        ShopManagement s = getById(id);
        ShopManagement shopManagement = s.setStatus(status);
        updateById(shopManagement);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult selectByClientIdAndShopIdGetShopDetail(Long shopId, Long clientId,Double longitude,Double latitude) {

        ShopManagement shopManagement = shopManagementMapper.selectById(shopId);

        double distance = getDistance(longitude, latitude, shopManagement.getLongitude(), shopManagement.getLatitude(),3);

        List<Coupon> couponList = couponMapper.selectList(new LambdaQueryWrapper<Coupon>().eq(Coupon::getShopId, shopManagement.getId().intValue()));
        List<CouponDto> couponDtoList = new ArrayList<>();
        for (Coupon coupon : couponList) {
            CouponDto couponDto = new CouponDto();
            BeanUtils.copyProperties(coupon,couponDto);
            Integer selectCount = couponStockMapper.selectCount(new LambdaQueryWrapper<CouponStock>().eq(CouponStock::getCouponId, coupon.getId()).ne(CouponStock::getStatus, "已领取"));
            if (selectCount<1){
                couponDto.setStatus("0");
            }
            Integer clientHold = couponStockMapper.selectClientHold(clientId,coupon.getId());
            if (clientHold > 0){
                couponDto.setClientHold("Y");
            }else {
                couponDto.setClientHold("N");
            }
            couponDtoList.add(couponDto);
        }
        ShopManagementDTO shopManagementDTO = new ShopManagementDTO();
        BeanUtils.copyProperties(shopManagement,shopManagementDTO);
        shopManagementDTO.setCouponList(couponDtoList);
        shopManagementDTO.setDistance(distance);
        Long count = shopManagementMapper.selectClientCollect(shopManagement.getId(),clientId);
        shopManagementDTO.setCollectFlag(count>0?1:0);
        return AjaxResult.success(shopManagementDTO);
    }

    /**
     * 根据经纬度，计算两点间的距离
     * @param longitudeFrom  第一个点的经度
     * @param latitudeFrom  第一个点的纬度
     * @param longitudeTo 第二个点的经度
     * @param latitudeTo  第二个点的纬度
     * @return 返回距离 单位米
     */
    public static double getDistance(double longitudeFrom, double latitudeFrom, double longitudeTo, double latitudeTo) {
        GlobalCoordinates source = new GlobalCoordinates(latitudeFrom, longitudeFrom);
        GlobalCoordinates target = new GlobalCoordinates(latitudeTo, longitudeTo);
        return new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.Sphere, source, target).getEllipsoidalDistance();
    }

    /**
     * 根据经纬度，计算两点间的距离
     * @param longitudeFrom  第一个点的经度
     * @param latitudeFrom  第一个点的纬度
     * @param longitudeTo 第二个点的经度
     * @param latitudeTo  第二个点的纬度
     * @param accurate  保留小数点几位
     * @return 返回距离 单位千米
     */
    public static double getDistance(double longitudeFrom, double latitudeFrom, double longitudeTo, double latitudeTo,int accurate) {
        double distance = getDistance(longitudeFrom, latitudeFrom, longitudeTo, latitudeTo);
        if (accurate < 0) {
            throw new RuntimeException("精确度必须是正整数或零");
        }
        return new BigDecimal(distance).divide(new BigDecimal(1000),accurate, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
}
